#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>

#include "Heros.h"



void initHeros (Heros* pheros, ArmePrincipale* parm_prin,
ArmeSecondaire* parm_sec1, ArmeSecondaire* parm_sec2, const int vie,
const float posX, const float posY, const float tailleX, const float tailleY)
{	
	assert (pheros != NULL && parm_prin != NULL && parm_sec1 != NULL && parm_sec2 != NULL 
		&& vie >= 0 && posX >= 0 && posY >= 0 && tailleX > 0 && tailleY > 0);
	initArmePrincipale (parm_prin);	
	initArmeSecondaire (parm_sec1, 0);
	initArmeSecondaire (parm_sec2, 1);
	pheros->parme_principale = parm_prin;
	pheros->parme_secondaire1 = parm_sec1;
	pheros->parme_secondaire2 = parm_sec2;
	pheros->vie_heros = vie;
	pheros->posX_heros = posX;
	pheros->posY_heros = posY;
	pheros->tailleX_heros = tailleX;
	pheros->tailleY_heros = tailleY;
}
 	

void libereHeros (Heros* pheros)
{	
	assert (pheros != NULL);
	detruireArmePrincipale (&(pheros->parme_principale));	
	detruireArmeSecondaire (&(pheros->parme_secondaire1));
	detruireArmeSecondaire (&(pheros->parme_secondaire2));
}

Heros* creerHeros (ArmePrincipale* parm_prin, ArmeSecondaire* parm_sec1, 
ArmeSecondaire* parm_sec2, const float vie,const float posX, const float posY,
const float tailleX, const float tailleY)
{
	assert (parm_prin != NULL && parm_sec1 != NULL && parm_sec2 != NULL && vie >= 0 
		&& posX >= 0 && posY >= 0 && tailleX > 0 && tailleY > 0);
	Heros* pheros = (Heros*) malloc (sizeof(Heros));
	initHeros (pheros, parm_prin, parm_sec1, parm_sec2, vie, posX, 
	posY, tailleX, tailleY);
	return pheros;
}

void detruireHeros (Heros** ppheros)
{	
	assert (ppheros != NULL && *ppheros != NULL);
	libereHeros (* ppheros);
	free (* ppheros);
	* ppheros = NULL;
}

ArmePrincipale* getArmePrincipale (const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->parme_principale;
}

ArmeSecondaire* getArmeSecondaire1 (const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->parme_secondaire1;
}

ArmeSecondaire* getArmeSecondaire2 (const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->parme_secondaire2;
}

const int getVieHeros(const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->vie_heros;
}

void setVieHeros(Heros* pheros, const int vie)
{
	assert (pheros != NULL && vie >= 0);
	pheros->vie_heros = vie;
}

const float getPosXHeros(const Heros* pheros)
{	
	assert (pheros != NULL);
	return pheros->posX_heros;
}

void setPosXHeros(Heros* pheros, const float posX)
{	
	assert (pheros != NULL && posX >= 0);
	pheros->posX_heros = posX;
}

const float getPosYHeros(const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->posY_heros;
}

void setPosYHeros(Heros* pheros, const float posY)
{
	assert (pheros != NULL && posY >= 0);
	pheros->posY_heros = posY;
}

const float getTailleXHeros(const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->tailleX_heros;
}

void setTailleXHeros(Heros* pheros, const float tailleX)
{
	assert (pheros != NULL && tailleX > 0);
	pheros->tailleX_heros = tailleX;
}

const float getTailleYHeros(const Heros* pheros)
{
	assert (pheros != NULL);
	return pheros->tailleY_heros;
}

void setTailleYHeros (Heros* pheros, const float tailleY)
{
	assert (pheros != NULL && tailleY>0);
	pheros->tailleY_heros = tailleY;
}

Tir* tirerHeros (Heros* pheros) //correspond au tir de l'arme principale
{
	assert (pheros != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros),getPosYHeros(pheros));  
	Point* pt2 = creerPoint(getPosXHeros(pheros),2);  // 2 car le tir du heros est vertical
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros), getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHeros2 (Heros* pheros)   //correspond au tir de la seconde arme principale
{
	assert (pheros != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros));
	Point* pt2 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, 2);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHerosObliqueGaucheHaut (Heros* pheros, Terrain* pterrain)   
{
	assert (pheros != NULL && pterrain != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros));
	Point* pt2 = creerPoint(0 , getPosYHeros(pheros)-150);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHerosObliqueDroiteHaut (Heros* pheros, Terrain* pterrain)   
{
	assert (pheros != NULL && pterrain != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros));
	Point* pt2 = creerPoint(getDimX_terrain(pterrain)-1 ,getPosYHeros(pheros)-150);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHerosObliqueGaucheMilieu (Heros* pheros, Terrain* pterrain)   
{
	assert (pheros != NULL && pterrain != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros));
	Point* pt2 = creerPoint(0 , getPosYHeros(pheros)-75);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHerosObliqueDroiteMilieu (Heros* pheros, Terrain* pterrain)   
{
	assert (pheros != NULL && pterrain != NULL);
	Point* pt1 = creerPoint(getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros));
	Point* pt2 = creerPoint(getDimX_terrain(pterrain)-1 ,getPosYHeros(pheros)-75);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 4.0);
	Tir* ptir = creerTir(10.0/8.0, 10.0/4.0, getPosXHeros(pheros)+getTailleXHeros(pheros)-1, getPosYHeros(pheros), ptraj, 0);
	return ptir;	
}

Tir* tirerHerosS1 (Heros* pheros)
{
	assert (pheros != NULL);
	setMunitions(pheros->parme_secondaire1, getMunitions(pheros->parme_secondaire1)-1);
	Point* pt1 = creerPoint(getPosXHeros(pheros) + 0.5*getTailleXHeros(pheros) -1 , getPosYHeros(pheros));
	Point* pt2 = creerPoint(getPosXHeros(pheros), 5);
	Trajectoire* ptraj = creerTrajectoire(pt1, pt2, 8.0);
	Tir* ptir = creerTir(15.0/8.0, 19.0/4.0, getPosXHeros(pheros) + 0.5*getTailleXHeros(pheros) -1, getPosYHeros(pheros), ptraj, 2);
	return ptir;    
}

Tir* tirerHerosS2 (Heros* pheros)
{
	assert (pheros != NULL);
	setMunitions(pheros->parme_secondaire2, getMunitions(pheros->parme_secondaire2)-1);
	Point* pt = creerPoint(0, 0);
	Trajectoire* ptraj = creerTrajectoire(pt, pt, 1.0);
	Tir* ptir = creerTir(1, 1, 0, 0, ptraj, 3);
	return ptir;
}

void enleverVie(Heros* pheros, int vie_moins)
{
	assert (pheros != NULL);
	assert (vie_moins > 0);
	if (getVieHeros(pheros) > vie_moins)
		 setVieHeros(pheros, getVieHeros(pheros) - vie_moins);
	else 
		 setVieHeros(pheros, 0);
}


const int terEstPositionHerosValide (const Terrain* pterrain,Heros* pheros, const float deplacementX,
	     const float deplacementY)

{
	assert (pterrain != NULL && pheros != NULL);
	if ((getPosXHeros(pheros)+deplacementX >= 0)&&(getPosXHeros(pheros)+getTailleXHeros(pheros)+deplacementX <= getDimX_terrain(pterrain))
	&&(getPosYHeros(pheros)+deplacementY >= 0)&&(getPosYHeros(pheros)+getTailleYHeros(pheros)+deplacementY <= getDimY_terrain(pterrain)))
		return 0; // la position est bonne
	return 1;	// la position n'est pas bonne
}

void deplacerHerosDroite (Heros* pheros, Terrain* pterrain)
{	assert (pheros != NULL && pterrain != NULL);
	if (terEstPositionHerosValide(pterrain,pheros, 2, 0) == 0)
		setPosXHeros(pheros, getPosXHeros(pheros) + 2);
}

void deplacerHerosGauche (Heros* pheros, Terrain* pterrain)
{	assert (pheros != NULL && pterrain != NULL);
	if (terEstPositionHerosValide(pterrain,pheros, -2, 0) == 0)
		setPosXHeros(pheros, getPosXHeros(pheros) - 2);
	}

void deplacerHerosHaut (Heros* pheros, Terrain* pterrain)
{	assert (pheros != NULL && pterrain != NULL);
	if (terEstPositionHerosValide(pterrain,pheros, 0, -3) == 0)
		setPosYHeros(pheros, getPosYHeros(pheros) - 3);
	}

void deplacerHerosBas (Heros* pheros, Terrain* pterrain)
{	
	assert (pheros != NULL && pterrain != NULL);
	if (terEstPositionHerosValide(pterrain, pheros, 0, 3) == 0)
		setPosYHeros(pheros, getPosYHeros(pheros) + 3);
  
}


/**@brief Cette procedure permet de tester toutes les fonctions du module*/
void testRegressionHeros ()
{	
	printf("On doit commencer par creer les armes avant de pouvoir creer le heros\n");
	ArmePrincipale* parm_printmp=creerArmePrincipale ();
	printf("creation arme principale reussie\n");
	printf("le niveau est %d et l'arme est a l'adresse %p\n\n",
	       parm_printmp->niveau_arme,parm_printmp);
	
	ArmeSecondaire* parm_sec1tmp=creerArmeSecondaire (0);
	printf("creation arme secondaire 1 reussie\n");
	printf("les munitions sont %d les degats sont %d et l arme est %p\n\n",
		parm_sec1tmp->munition_secondaire, parm_sec1tmp->degat_arme_secondaire, 
		parm_sec1tmp);
	
	ArmeSecondaire* parm_sec2tmp=creerArmeSecondaire (1);
	printf("creation arme secondaire 2 reussie\n");
	printf("les munitions sont %d les degats sont %d et l arme est %p\n\n",
		parm_sec2tmp->munition_secondaire, parm_sec2tmp->degat_arme_secondaire, 
		parm_sec2tmp);
	
	detruireArmePrincipale (&parm_printmp);
	printf("apres destuction l'adresse de l'arme principale devrait etre nulle elle est %p\n\n",
		parm_printmp);
	detruireArmeSecondaire (&(parm_sec1tmp));
	printf("apres destruction l'arme sec1 est %p\n\n",parm_sec1tmp);
	detruireArmeSecondaire (&(parm_sec2tmp));
	printf("apres destruction l'arme sec2 est %p\n\n",parm_sec2tmp);
	
	printf("on a verifie la creation et la destructions des armes\n\n");
	
	printf("on va passer au heros\n\n");
	
	ArmePrincipale* parm_prin=creerArmePrincipale ();
	printf("le niveau est %d \n\n",parm_prin->niveau_arme);
	ArmeSecondaire* parm_sec1=creerArmeSecondaire (0);
	ArmeSecondaire* parm_sec2=creerArmeSecondaire (1);
	printf("les munitions sont %d les degats sont %d et l arme est %p\n\n",
	       parm_sec2->munition_secondaire, parm_sec2->degat_arme_secondaire, parm_sec2);
	
	Heros heros;
	setPosXHeros (&heros, 11.55);
	setVieHeros (&heros, 200);
	
	printf("%p %p %p,%p %d %f\n\n",&heros, parm_prin, parm_sec1, 
	       parm_sec2, heros.vie_heros, heros.posX_heros);
	
	
	initHeros (&heros, parm_prin, parm_sec1, parm_sec2, 100, 10.36,
	10.75, 20.5, 20.25 );
	printf("%p %p,%p, %p %d %f\n",&heros, heros.parme_principale, heros.parme_secondaire1,
		 heros.parme_secondaire2, heros.vie_heros, heros.posX_heros);
	
	printf("initialisation du heros %p reussie\n\n",&heros);
	
	printf("la vie du heros devrait etre 100 elle est %d et le valeur du get est %d \n\n",
	heros.vie_heros, getVieHeros(&heros));

	printf("changeons maintenant la vie du heros mettons la a 200\n\n");
	setVieHeros (&heros,200);
	printf("la vie du heros devrait etre 200 elle est %d et le valeur du get est %d \n\n",
	heros.vie_heros, getVieHeros(&heros));
	
	printf("effectuons un dernier changement avec la valeur 1000000\n\n");
	setVieHeros (&heros,1000000);
	printf("la vie du heros devrait etre 1000000 elle est %d et la valeur du get est %d \n\n",
	heros.vie_heros, getVieHeros(&heros));
	
	printf("on enleve 500000 à vie du hero\n\n");
	enleverVie (&heros,500000);
	printf("la vie du heros devrait etre 500000 elle est %d et la valeur du get est %d \n\n",
	heros.vie_heros, getVieHeros(&heros));
	
	printf("on enleve 400000 à vie du hero\n\n");
	enleverVie (&heros,400000);
	printf("la vie du heros devrait etre 100000 elle est %d et la valeur du get est %d \n\n",
	heros.vie_heros, getVieHeros(&heros));
	
	printf("testons maintenant les changements de positions et de taille\n");
	printf("les valeurs d'origine devraient etre 10.36, 10.75, 20.5, 20.25 \
elles sont %f, %f, %f, %f\n\n",heros.posX_heros,
	       heros.posY_heros, heros.tailleX_heros, heros.tailleY_heros);
	printf("les valeurs fournies par les accesseurs sont %f, %f, %f, %f\n\n",
		getPosXHeros(&heros),getPosYHeros(&heros),
		getTailleXHeros(&heros),getTailleYHeros(&heros));
	
	Heros* psuperheros=creerHeros (parm_prin, parm_sec1, parm_sec2, 100, 10,
	10, 20, 20 );
	printf("%p %p,%p,%p %d %f\n\n",psuperheros, parm_prin, parm_sec1, parm_sec2, 
		psuperheros->vie_heros, psuperheros->posX_heros);
	
	Tir* ptirr=tirerHeros (psuperheros);
	printf("ptirr : %p\n",ptirr);
	printf("le super heros tire\n");
	
	printf("posx: %f, posy: %f\n", getPosXTir(ptirr), getPosYTir(ptirr));
		
	deplacerTir (ptirr);
	printf("le tir se déplace\n");
	
	printf("posx: %f, posy: %f\n",getPosXTir(ptirr), getPosYTir(ptirr));
		
	deplacerTir (ptirr);
	printf("le tir se déplace\n");
	
	printf("posx: %f, posy: %f\n",getPosXTir(ptirr), getPosYTir(ptirr));
		
	deplacerTir (ptirr);
	printf("le tir se déplace\n");
	
	printf("posx: %f, posy: %f\n\n",getPosXTir(ptirr), getPosYTir(ptirr));
		
		
		
	detruireHeros (&(psuperheros));
	printf("apres destruction cette adresse devrait etre nulle  %p \n\n",psuperheros);
	printf("la creation et la destruction du heros fonctionnent\n");

  
}


